Strategy Pattern
2 min readStrategy Pattern
TL;DR
Encapsulate different trading algorithms or execution strategies under a common interface.
How it works
🧩 Example — Switching between Aggressive and Passive strategies
public interface ITradeStrategy
{
void Execute(Order order);
}
public class AggressiveStrategy : ITradeStrategy
{
public void Execute(Order order)
{
Console.WriteLine($"[Aggressive] Sending order {order.Symbol} immediately at market price");
}
}
public class PassiveStrategy : ITradeStrategy
{
public void Execute(Order order)
{
Console.WriteLine($"[Passive] Placing limit order for {order.Symbol} to wait for better price");
}
}
public class Trader
{
private readonly ITradeStrategy _strategy;
public Trader(ITradeStrategy strategy) => _strategy = strategy;
public void Trade(Order order) => _strategy.Execute(order);
}
// --- Usage ---
var order = new Order { Symbol = "EURUSD", Amount = 1000 };
var trader = new Trader(new AggressiveStrategy());
trader.Trade(order); // can switch strategy dynamically
✅ Why it matters:
- Switch trading behaviors (aggressive, passive, hedging) dynamically.
- Avoids
if/elsehell. - New strategies plug in easily without code modification.
Quick recall Q&A
When behavior varies by configuration, tenant, or runtime data (e.g., aggressive vs passive execution) and you want to encapsulate algorithms behind a shared interface instead of branching all over the codebase.
Inject a factory that chooses the correct ITradeStrategy based on market conditions, order metadata, or feature flags. Strategies can be swapped via DI or resolved dynamically.
Strategy changes behavior per request/order; State models transitions over time. Strategy is stateless and pluggable, whereas State encapsulates transitions inside the object.
Instantiate each strategy with fake dependencies and assert their behavior independently. Tests stay small because the interface isolates algorithms from the rest of the system.
Combine Strategy with Factory or Specification. The factory encapsulates selection logic; strategies stay focused on execution.
Group related variations via configuration or policy objects, and extract shared behavior into base classes or decorators. Only add new strategies when behavior genuinely differs.
They should be stateless or encapsulate state tightly (e.g., cached calculations). For long-lived state machines, consider the State pattern or per-order context objects passed into strategies.
Register strategies and inject them via constructor or keyed services, enabling easy swapping in tests and runtime. Feature flags can toggle which strategy is resolved.
Decorate strategies or wrap them with interceptors to log execution time and outcomes. This keeps telemetry consistent regardless of which strategy executed.
Minimal—just an extra virtual call. The clarity and extensibility gained typically outweigh the small overhead, especially compared to complex branching logic.